package cn.superchart.web.core.handler;
import cn.superchart.common.base.BaseResult;
import cn.superchart.common.exception.ScException;
import cn.superchart.common.utils.RequestContextUtil;
import jakarta.validation.ConstraintViolation;
import jakarta.validation.ConstraintViolationException;
import jakarta.validation.UnexpectedTypeException;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.exceptions.PersistenceException;
import org.mybatis.spring.MyBatisSystemException;
import org.springframework.http.HttpStatus;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.LockedException;
import org.springframework.validation.BindException;
import org.springframework.validation.ObjectError;
import org.springframework.web.HttpMediaTypeNotSupportedException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.multipart.MultipartException;
import org.springframework.web.multipart.support.MissingServletRequestPartException;
import org.springframework.web.servlet.resource.NoResourceFoundException;

import java.util.List;
import java.util.Set;


@Slf4j
public class ScExceptionUtil {
    public static BaseResult<String> convert(Exception e) {
        return switch (e) {
            case HttpRequestMethodNotSupportedException ex -> handleMethodNotSupported(ex);
            case HttpMessageNotReadableException ex -> handleMessageNotReadable(ex);
            case HttpMediaTypeNotSupportedException ex -> handleMediaTypeNotSupported(ex);
            case MethodArgumentNotValidException ex -> handleMethodArgumentNotValid(ex);
            case NoResourceFoundException ex -> handleNoResourceFound(ex);
            case BindException ex -> handleBindException(ex);
            case UnexpectedTypeException ex -> handleUnexpectedType(ex);
            case BadCredentialsException ex -> handleBadCredentials(ex);
            case LockedException ex-> handleLocked(ex);
            case ConstraintViolationException ex -> handleConstraintViolation(ex);
            case MissingServletRequestParameterException ex -> BaseResult.by(HttpStatus.BAD_REQUEST.value(), ex.getMessage(), null);
            case MultipartException ex -> handleMultipartException(ex);
            case MissingServletRequestPartException ignored -> BaseResult.error("请选择要上传的文件并检查文件参数名称是否正确");
            case MyBatisSystemException ex -> handleMyBatisException(ex);
            case ScException ex -> BaseResult.by(ex.getCode(), ex.getMsg(), null);
            default -> handleUnknownException(e);
        };
    }
    
    private static BaseResult<String> handleMethodNotSupported(HttpRequestMethodNotSupportedException e) {
        String method = RequestContextUtil.getCurrentRequest().getMethod();
        if ("GET".equals(method)) {
            return BaseResult.by(HttpStatus.METHOD_NOT_ALLOWED.value(), "请求方法应为POST", null);
        } else if ("POST".equals(method)) {
            return BaseResult.by(HttpStatus.METHOD_NOT_ALLOWED.value(), "请求方法应为GET", null);
        } else {
            return BaseResult.by(HttpStatus.METHOD_NOT_ALLOWED.value(), "请求方法仅支持GET或POST", null);
        }
    }

    private static BaseResult<String> handleMessageNotReadable(HttpMessageNotReadableException e) {
        log.error("参数传递格式异常：", e);
        if (e.getMessage() != null && e.getMessage().contains("JSON parse error")) {
            return BaseResult.by(HttpStatus.UNSUPPORTED_MEDIA_TYPE.value(), "参数格式错误", null);
        } else {
            return BaseResult.by(HttpStatus.UNSUPPORTED_MEDIA_TYPE.value(), "请使用JSON方式传参", null);
        }
    }

    private static BaseResult<String> handleMediaTypeNotSupported(HttpMediaTypeNotSupportedException e) {
        log.error("参数传递格式异常：", e);
        return BaseResult.by(HttpStatus.UNSUPPORTED_MEDIA_TYPE.value(), "参数格式错误", null);
    }

    private static BaseResult<String> handleMethodArgumentNotValid(MethodArgumentNotValidException e) {
        return BaseResult.by(HttpStatus.UNSUPPORTED_MEDIA_TYPE.value(),
                getValidationMessage(e.getBindingResult().getAllErrors()), null);
    }

    private static BaseResult<String> handleBadCredentials(BadCredentialsException e) {
        return BaseResult.by(HttpStatus.FORBIDDEN.value(),e.getMessage(), null);
    }

    private static BaseResult<String> handleLocked(LockedException e) {
        return BaseResult.by(HttpStatus.FORBIDDEN.value(),e.getMessage(), null);
    }

    private static BaseResult<String> handleNoResourceFound(NoResourceFoundException e) {
        return BaseResult.by(HttpStatus.NOT_FOUND.value(),e.getMessage(), null);
    }



    private static BaseResult<String> handleBindException(BindException e) {
        return BaseResult.by(HttpStatus.UNSUPPORTED_MEDIA_TYPE.value(),
                getValidationMessage(e.getBindingResult().getAllErrors()), null);
    }

    private static BaseResult<String> handleUnexpectedType(UnexpectedTypeException e) {
        return BaseResult.by(HttpStatus.UNSUPPORTED_MEDIA_TYPE.value(),"参数校验类型异常,请检查校验注解是否正确!", null);
    }


    private static BaseResult<String> handleConstraintViolation(ConstraintViolationException e) {
        return BaseResult.by(HttpStatus.UNSUPPORTED_MEDIA_TYPE.value(),
                getValidationMessage(e.getConstraintViolations()), null);
    }

    private static BaseResult<String> handleMultipartException(MultipartException e) {
        log.error("文件上传参数异常：", e);
        return BaseResult.error("请使用multipart/form-data方式上传文件");
    }

    private static BaseResult<String> handleMyBatisException(MyBatisSystemException e) {
        Throwable cause = e.getCause();
        if (cause instanceof PersistenceException) {
            Throwable secondCause = cause.getCause();
            if (secondCause instanceof ScException) {
                ScException commonException = (ScException) secondCause;
                return BaseResult.by(commonException.getCode(), commonException.getMsg(), null);
            } else {
                log.error("数据操作异常：", e);
                return BaseResult.error("数据操作异常");
            }
        } else {
            log.error("数据操作异常：", e);
            return BaseResult.error("数据操作异常");
        }
    }

    private static BaseResult<String> handleUnknownException(Exception e) {
        log.error("服务器未知异常，请求地址：{}，具体信息：",  RequestContextUtil.getCurrentRequest().getRequestURL(), e);
        return BaseResult.error( "未知异常地址:{}", RequestContextUtil.getCurrentRequest().getRequestURL().toString());
    }

    /**
     * 获取校验错误信息
     */
    private static String getValidationMessage(List<ObjectError> allErrors) {
        StringBuilder message = new StringBuilder();
        for (ObjectError error : allErrors) {
            message.append(error.getDefaultMessage());
            break;
        }
        return message.toString();
    }

    /**
     * 获取约束校验错误信息
     */
    private static String getValidationMessage(Set<ConstraintViolation<?>> violations) {
        StringBuilder message = new StringBuilder();
        for (ConstraintViolation<?> violation : violations) {
            message.append(violation.getMessage());
            break;
        }
        return message.toString();
    }
}
